home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 2: CDPD 1 / Almathera Ten on Ten - Disc 2: CDPD 1.iso / pd / 076-100 / 085 / csh / execom.c < prev    next >
C/C++ Source or Header  |  1995-03-13  |  16KB  |  695 lines

  1. /*
  2.  * EXECOM.C
  3.  *
  4.  * Matthew Dillon, 10 August 1986
  5.  *    Finally re-written.
  6.  *
  7.  * version 2.06M (Manx Version and Additions) by Steve Drew 28-May-87
  8.  *
  9.  *
  10.  */
  11.  
  12. #include "shell.h"
  13.  
  14. #define F_EXACT 0
  15. #define F_ABBR    1
  16.  
  17. #define ST_COND      0x03
  18. #define ST_NAME      0x02
  19. #define ST_NOEXP  0x04
  20.  
  21. int has_wild = 0;          /* set if any arg has wild card */
  22.  
  23. struct COMMAND {
  24.    int (*func)();
  25.    short minargs;
  26.    short stat;
  27.    int     val;
  28.    char *name;
  29. };
  30.  
  31. extern char *format_insert_string();
  32. extern char *mpush(), *exarg();
  33.  
  34. extern int do_run(), do_number();
  35. extern int do_quit(), do_set_var(), do_unset_var();
  36. extern int do_echo(), do_source(), do_mv();
  37. extern int do_cd(), do_pwd(), do_rm(), do_mkdir(), do_history();
  38. extern int do_mem(), do_cat(), do_dir(), do_devinfo(), do_inc();
  39. extern int do_foreach(), do_return(), do_if(), do_label(), do_goto();
  40. extern int do_input(), do_ver(), do_sleep(), do_help();
  41. extern int do_strhead(), do_strtail();
  42. extern int do_copy(), date(),  do_ps();
  43. extern int do_forever(), do_abortline();
  44.  
  45. static struct COMMAND Command[] = {
  46.    do_run      , 0,  0,         0 ,   "\001",
  47.    do_number   , 0,  0,         0 ,   "\001",
  48.    do_set_var  , 0,  0, LEVEL_ALIAS,   "alias",
  49.    do_abortline, 0,  0,         0,    "abortline",
  50.    do_cd       , 0,  0,         0 ,   "cd",
  51.    do_cat      , 0,  0,         0 ,   "cat",
  52.    do_copy     , 1,  0,         0 ,   "copy",
  53.    date           , 0,  0,         0 ,   "date",
  54.    do_dir      , 0,  ST_NOEXP,     0 ,   "dir",
  55.    do_inc      , 1,  0,        -1 ,   "dec",
  56.    do_devinfo  , 0,  0,         0 ,   "devinfo",
  57.    do_echo     , 0,  0,         0 ,   "echo",
  58.    do_if       , 0,  ST_COND,     1 ,   "else",
  59.    do_if       , 0,  ST_COND,     2 ,   "endif",
  60.    do_foreach  , 3,  0,         0 ,   "foreach",
  61.    do_forever  , 1,  0,         0 ,   "forever",
  62.    do_goto     , 1,  0,         0 ,   "goto",
  63.    do_help     , 0,  0,         0 ,   "help",
  64.    do_history  , 0,  0,         0 ,   "history",
  65.    do_if       , 1,  ST_COND,     0 ,   "if",
  66.    do_inc      , 1,  0,         1 ,   "inc",
  67.    do_input    , 1,  0,         0 ,   "input",
  68.    do_label    , 1,  ST_COND,     0 ,   "label",
  69.    do_mem      , 0,  0,         0 ,   "mem",
  70.    do_mkdir    , 0,  0,         0 ,   "mkdir",
  71.    do_mv       , 2,  0,         0 ,   "mv",
  72.    do_ps       , 0,  0,         0,    "ps",
  73.    do_pwd      , 0,  0,         0 ,   "pwd",
  74.    do_quit     , 0,  0,         0 ,   "quit",
  75.    do_return   , 0,  0,         0 ,   "return",
  76.    do_rm       , 0,  0,         0 ,   "rm",
  77.    do_run      , 1,  ST_NAME,     0 ,   "run",
  78.    do_set_var  , 0,  0, LEVEL_SET  ,   "set",
  79.    do_sleep    , 0,  0,         0,    "sleep",
  80.    do_source   , 0,  0,         0 ,   "source",
  81.    do_strhead  , 3,  0,         0 ,   "strhead",
  82.    do_strtail  , 3,  0,         0 ,   "strtail",
  83.    do_unset_var, 0,  0, LEVEL_ALIAS,   "unalias",
  84.    do_unset_var, 0,  0, LEVEL_SET  ,   "unset",
  85.    do_ver      , 0,  0,         0 ,   "version",
  86.    '\0'           , 0,  0,         0 ,   NULL
  87. };
  88.  
  89.  
  90. static unsigned char elast;         /* last end delimeter */
  91. static char Cin_ispipe, Cout_ispipe;
  92.  
  93. exec_command(base)
  94. char *base;
  95. {
  96.    register char *scr;
  97.    register int i;
  98.    char buf[32];
  99.  
  100.    if (!H_stack) {
  101.       add_history(base);
  102.       sprintf(buf, "%d", H_tail_base + H_len);
  103.       set_var(LEVEL_SET, V_HISTNUM, buf);
  104.    }
  105.    scr = malloc((strlen(base) << 2) + 2);    /* 4X */
  106.    preformat(base, scr);
  107.    i = fcomm(scr, 1);
  108.    return ((i) ? -1 : 1);
  109. }
  110.  
  111. isalphanum(c)
  112. char c;
  113. {
  114.    if (c >= '0' && c <= '9')
  115.       return (1);
  116.    if (c >= 'a' && c <= 'z')
  117.       return (1);
  118.    if (c >= 'A' && c <= 'Z')
  119.       return (1);
  120.    if (c == '_')
  121.       return (1);
  122.    return (0);
  123. }
  124.  
  125. preformat(s, d)
  126. register char *s, *d;
  127. {
  128.    register int si, di, qm;
  129.  
  130.    si = di = qm = 0;
  131.    while (s[si] == ' ' || s[si] == 9)
  132.       ++si;
  133.    while (s[si]) {
  134.       if (qm && s[si] != '\"' && s[si] != '\\') {
  135.      d[di++] = s[si++] | 0x80;
  136.      continue;
  137.       }
  138.       switch (s[si]) {
  139.       case ' ':
  140.       case 9:
  141.      d[di++] = ' ';
  142.      while (s[si] == ' ' || s[si] == 9)
  143.         ++si;
  144.      if (s[si] == 0 || s[si] == '|' || s[si] == ';')
  145.         --di;
  146.      break;
  147.       case '*':
  148.       case '?':
  149.      d[di++] = 0x80;
  150.       case '!':
  151.      d[di++] = s[si++];
  152.      break;
  153.       case '#':
  154.      d[di++] = '\0';
  155.      while (s[si])
  156.         ++si;
  157.      break;
  158.       case ';':
  159.       case '|':
  160.      d[di++] = s[si++];
  161.      while (s[si] == ' ' || s[si] == 9)
  162.         ++si;
  163.      break;
  164.       case '\\':
  165.      d[di++] = s[++si] | 0x80;
  166.      if (s[si]) ++si;
  167.      break;
  168.       case '\"':
  169.      qm = 1 - qm;
  170.      ++si;
  171.      break;
  172.       case '^':
  173.      d[di++] = s[++si] & 0x1F;
  174.      if (s[si]) ++si;
  175.      break;
  176.       case '$':        /* search end of var name and place false space */
  177.      d[di++] = 0x80;
  178.      d[di++] = s[si++];
  179.      while (isalphanum(s[si]))
  180.         d[di++] = s[si++];
  181.      d[di++] = 0x80;
  182.      break;
  183.       default:
  184.      d[di++] = s[si++];
  185.      break;
  186.       }
  187.    }
  188.    d[di++] = 0;
  189.    d[di]   = 0;
  190.    if (debug & 0x01) {
  191.       fprintf (stderr,"PREFORMAT: %d :%s:\n", strlen(d), d);
  192.    }
  193. }
  194.  
  195. /*
  196.  * process formatted string.  ' ' is the delimeter.
  197.  *
  198.  *    0: check '\0': no more, stop, done.
  199.  *    1: check $.     if so, extract, format, insert
  200.  *    2: check alias. if so, extract, format, insert. goto 1
  201.  *    3: check history or substitution, extract, format, insert. goto 1
  202.  *
  203.  *    4: assume first element now internal or disk based command.
  204.  *
  205.  *    5: extract each ' ' or 0x80 delimited argument and process, placing
  206.  *     in av[] list (except 0x80 args appended).  check in order:
  207.  *
  208.  *           '$'       insert string straight
  209.  *           '>'       setup stdout
  210.  *           '>>'       setup stdout flag for append
  211.  *           '<'       setup stdin
  212.  *           '*' or '?'  do directory search and insert as separate args.
  213.  *
  214.  *           ';' 0 '|'   end of command.  if '|' setup stdout
  215.  *                -execute command, fix stdin and out (|) sets
  216.  *                 up stdin for next guy.
  217.  */
  218.  
  219.  
  220. fcomm(str, freeok)
  221. register char *str;
  222. {
  223.    static int alias_count;
  224.    int p_alias_count = 0;
  225.    char *istr;
  226.    char *nextstr;
  227.    char *command;
  228.    char *pend_alias = NULL;
  229.    char err = 0;
  230.    has_wild = 0;
  231.    ++alias_count;
  232.  
  233.    mpush_base();
  234.    if (*str == 0)
  235.       goto done1;
  236. step1:
  237.    if (alias_count == MAXALIAS || ++p_alias_count == MAXALIAS) {
  238.       fprintf(stderr,"Alias Loop\n");
  239.       err = 20;
  240.       goto done1;
  241.    }
  242.    if (*str == '$') {
  243.       if (istr = get_var (LEVEL_SET, str + 1))
  244.      str = format_insert_string(str, istr, &freeok);
  245.    }
  246.    istr = NULL;
  247.    if (*(unsigned char *)str < 0x80)
  248.       istr = get_var (LEVEL_ALIAS, str);  /* only if not \command */
  249.    *str &= 0x7F;              /* remove \ teltail      */
  250.    if (istr) {
  251.       if (*istr == '%') {
  252.      pend_alias = istr;
  253.       } else {
  254.      str = format_insert_string(str, istr, &freeok);
  255.      goto step1;
  256.       }
  257.    }
  258.    if (*str == '!') {
  259.       char *p, c;              /* fix to allow !cmd1;!cmd2 */
  260.       for(p = str; *p && *p != ';' ; ++p);
  261.       c = *p;
  262.       *p = '\0';
  263.       istr = get_history(str);
  264.       *p = c;
  265.       replace_head(istr);
  266.       str = format_insert_string(str, istr, &freeok);
  267.       goto step1;
  268.    }
  269.    nextstr = str;
  270.    command = exarg(&nextstr);
  271.    if (*command == 0)
  272.       goto done0;
  273.    if (pend_alias == 0) {
  274.       register int ccno;
  275.       ccno = find_command(command);
  276.       if (Command[ccno].stat & ST_COND)
  277.      goto skipgood;
  278.    }
  279.    if (disable) {
  280.       while (elast && elast != ';' && elast != '|')
  281.      exarg(&nextstr);
  282.       goto done0;
  283.    }
  284. skipgood:
  285.    {
  286.       register char *arg, *ptr, *scr;
  287.       short redir;
  288.       short doexpand;
  289.       short cont;
  290.       short inc;
  291.  
  292.       ac = 1;
  293.       av[0] = command;
  294. step5:                        /* ac = nextac */
  295.       if (!elast || elast == ';' || elast == '|')
  296.      goto stepdone;
  297.  
  298.       av[ac] = '\0';
  299.       cont = 1;
  300.       doexpand = redir = inc = 0;
  301.  
  302.       while (cont && elast) {
  303.      int ccno = find_command(command);
  304.      ptr = exarg(&nextstr);
  305.      inc = 1;
  306.      arg = "";
  307.      cont = (elast == 0x80);
  308.      switch (*ptr) {
  309.      case '<':
  310.         redir = -2;
  311.      case '>':
  312.         if (Command[ccno].stat & ST_NAME) {
  313.                             /* don't extract   */
  314.         redir = 0;                /* <> stuff if its */
  315.         arg = ptr;                /* external cmd.   */
  316.         break;
  317.         }
  318.         ++redir;
  319.         arg = ptr + 1;
  320.         if (*arg == '>') {
  321.            redir = 2;     /* append >> (not impl yet) */
  322.            ++arg;
  323.         }
  324.         cont = 1;
  325.         break;
  326.      case '$':
  327.         if ((arg = get_var(LEVEL_SET, ptr + 1)) == NULL)
  328.            arg = ptr;
  329.         break;
  330.      case '*':
  331.      case '?':
  332.         if ((Command[ccno].stat & ST_NOEXP) == 0)
  333.            doexpand = 1;
  334.         arg = ptr;
  335.         break;
  336.      default:
  337.         arg = ptr;
  338.         break;
  339.      }
  340.  
  341.      /* Append arg to av[ac] */
  342.  
  343.      for (scr = arg; *scr; ++scr)
  344.         *scr &= 0x7F;
  345.      if (av[ac]) {
  346.         register char *old = av[ac];
  347.         av[ac] = mpush(strlen(arg)+1+strlen(av[ac]));
  348.         strcpy(av[ac], old);
  349.         strcat(av[ac], arg);
  350.      } else {
  351.         av[ac] = mpush(strlen(arg)+1);
  352.         strcpy(av[ac], arg);
  353.      }
  354.      if (elast != 0x80)
  355.         break;
  356.       }
  357.  
  358.       /* process expansion */
  359.  
  360.       if (doexpand) {
  361.      char **eav, **ebase;
  362.      int eac;
  363.      has_wild = 1;
  364.      eav = ebase = expand(av[ac], &eac);
  365.      inc = 0;
  366.      if (eav) {
  367.         if (ac + eac + 2 > MAXAV) {
  368.            ierror (NULL, 506);
  369.            err = 1;
  370.         } else {
  371.            QuickSort(eav, eac);
  372.            for (; eac; --eac, ++eav)
  373.           av[ac++] = strcpy(mpush(strlen(*eav)+1), *eav);
  374.         }
  375.         free_expand (ebase);
  376.      }
  377.       }
  378.  
  379.       /* process redirection  */
  380.  
  381.       if (redir && !err) {
  382.      register char *file = (doexpand) ? av[--ac] : av[ac];
  383.  
  384.      if (redir < 0)
  385.         Cin_name = file;
  386.      else {
  387.         Cout_name = file;
  388.         Cout_append = (redir == 2);
  389.      }
  390.      inc = 0;
  391.       }
  392.  
  393.       /* check elast for space */
  394.  
  395.       if (inc) {
  396.      ++ac;
  397.      if (ac + 2 > MAXAV) {
  398.         ierror (NULL, 506);
  399.         err = 1;            /* error condition */
  400.         elast = 0;            /* don't process any more arguemnts */
  401.      }
  402.       }
  403.       if (elast == ' ')
  404.      goto step5;
  405.    }
  406. stepdone:
  407.    av[ac] = '\0';
  408.  
  409.    /* process pipes via files */
  410.  
  411.    if (elast == '|' && !err) {
  412.       static int which;            /* 0 or 1 in case of multiple pipes */
  413.       which = 1 - which;
  414.       Cout_name = (which) ? Pipe1 : Pipe2;
  415.       Cout_ispipe = 1;
  416.    }
  417.  
  418.  
  419.    if (err)
  420.       goto done0;
  421.  
  422.    {
  423.       register int i, len;
  424.       char save_elast;
  425.       register char *avline;
  426.  
  427.       save_elast = elast;
  428.       for (i = len = 0; i < ac; ++i)
  429.      len += strlen(av[i]) + 1;
  430.       avline = malloc(len+1);
  431.       for (len = 0, i = ((pend_alias) ? 1 : 0); i < ac; ++i) {
  432.      if (debug & 0x02) {
  433.          fprintf (stderr, "AV[%2d] %d :%s:\n", i, strlen(av[i]), av[i]);
  434.      }
  435.      strcpy(avline + len, av[i]);
  436.      len += strlen(av[i]);
  437.      if (i + 1 < ac)
  438.         avline[len++] = ' ';
  439.       }
  440.       avline[len] = 0;
  441.       if (pend_alias) {                      /* special % alias */
  442.      register char *ptr, *scr;
  443.      for (ptr = pend_alias; *ptr && *ptr != ' '; ++ptr);
  444.      set_var (LEVEL_SET, pend_alias + 1, avline);
  445.      free (avline);
  446.  
  447.      scr = malloc((strlen(ptr) << 2) + 2);
  448.      preformat (ptr, scr);
  449.      fcomm (scr, 1);
  450.      unset_var (LEVEL_SET, pend_alias + 1);
  451.       } else {                          /* normal command     */
  452.      register int ccno;
  453.      long  oldcin = (long)Input();
  454.      long  oldcout = (long)Output();
  455.  
  456. #ifndef AZTEC_C
  457.      extern struct _dev _devtab[];
  458. #endif
  459.      struct _dev *stdfp;
  460.  
  461.      fflush(stdout);
  462.      ccno = find_command (command);
  463.      if ((Command[ccno].stat & ST_NAME) == 0) {
  464.         if (Cin_name) {
  465.            if ((Cin = (long)Open(Cin_name,1005L)) == 0L) {
  466.           ierror (NULL, 504);
  467.           err = 1;
  468.           Cin_name = '\0';
  469.            } else {
  470.           Myprocess->pr_CIS = Cin;
  471.           _devtab[stdin->_unit].fd = Cin;
  472.            }
  473.         }
  474.         if (Cout_name) {
  475.            if (Cout_append) {
  476.           if ((Cout = (long)Open(Cout_name, 1005L)) != 0L)
  477.              Seek(Cout, 0L, 1L);
  478.            } else {
  479.           Cout = (long)Open(Cout_name,1006L);
  480.            }
  481.            if (Cout == NULL) {
  482.           err = 1;
  483.           ierror (NULL, 504);
  484.           Cout_name = '\0';
  485.           Cout_append = 0;
  486.            } else {
  487.           Myprocess->pr_COS = Cout;
  488.           _devtab[stdout->_unit].fd = Cout;
  489.            }
  490.         }
  491.      }
  492.      if (ac < Command[ccno].minargs + 1) {
  493.         ierror (NULL, 500);
  494.         err = -1;
  495.      } else if (!err) {
  496.         i = (*Command[ccno].func)(avline, Command[ccno].val);
  497.         if (i < 0)
  498.            i = 20;
  499.         err = i;
  500.      }
  501.      free (avline);
  502.      if (Exec_ignoreresult == 0 && Lastresult != err) {
  503.         Lastresult = err;
  504.         seterr();
  505.      }
  506.      if ((Command[ccno].stat & ST_NAME) == 0) {
  507.         if (Cin_name) {
  508.            fflush(stdin);
  509.            clearerr(stdin);
  510.            Close(Cin);
  511.         }
  512.         if (Cout_name) {
  513.            fflush(stdout);
  514.            clearerr(stdout);
  515.            stdout->_flags &= ~_DIRTY;    /* because of nil: device */
  516.            Close(Cout);
  517.            Cout_append = 0;
  518.         }
  519.      }
  520.  
  521.      /* the next few lines solve a bug with fexecv and bcpl programs */
  522.      /* that muck up the input/output streams  which causes GURUs    */
  523.  
  524.      Myprocess->pr_CIS =  _devtab[stdin->_unit].fd = oldcin;
  525.      Myprocess->pr_COS =  _devtab[stdout->_unit].fd = oldcout;
  526.       }
  527.       if (Cin_ispipe && Cin_name)
  528.      DeleteFile(Cin_name);
  529.       if (Cout_ispipe) {
  530.      Cin_name = Cout_name;           /* ok to assign.. static name */
  531.      Cin_ispipe = 1;
  532.       } else {
  533.      Cin_name = '\0';
  534.       }
  535.       Cout_name = '\0';
  536.       Cout_ispipe = 0;
  537.       elast = save_elast;
  538.    }
  539.    mpop_tobase();               /* free arguments   */
  540.    mpush_base();               /* push dummy base  */
  541.  
  542. done0:
  543.    {
  544.       char *str;
  545.       if (err && E_stack == 0) {
  546.      str = get_var(LEVEL_SET, V_EXCEPT);
  547.      if (err >= ((str)?atoi(str):1)) {
  548.         if (str) {
  549.            ++H_stack;
  550.            ++E_stack;
  551.            exec_command(str);
  552.            --E_stack;
  553.            --H_stack;
  554.         } else {
  555.            Exec_abortline = 1;
  556.         }
  557.      }
  558.       }
  559.       if (elast != 0 && Exec_abortline == 0)
  560.      err = fcomm(nextstr, 0);
  561.       Exec_abortline = 0;
  562.       if (Cin_name)
  563.      DeleteFile(Cin_name);
  564.       Cin_name = NULL;
  565.       Cin_ispipe = 0;
  566.    }
  567. done1:
  568.    mpop_tobase();
  569.    if (freeok)
  570.       free(str);
  571.    --alias_count;
  572.    return ((int)err);               /* TRUE = error occured      */
  573. }
  574.  
  575.  
  576. char *
  577. exarg(ptr)
  578. unsigned char **ptr;
  579. {
  580.    register unsigned char *end;
  581.    register unsigned char *start;
  582.  
  583.    start = end = *ptr;
  584.    while (*end && *end != 0x80 && *end != ';' && *end != '|' && *end != ' ')
  585.       ++end;
  586.    elast = *end;
  587.    *end = '\0';
  588.    *ptr = end + 1;
  589.    return ((char *)start);
  590. }
  591.  
  592. static char **Mlist;
  593.  
  594. mpush_base()
  595. {
  596.    char *str;
  597.  
  598.    str = malloc(5);
  599.    *(char ***)str = Mlist;
  600.    str[4] = 0;
  601.    Mlist = (char **)str;
  602. }
  603.  
  604. char *
  605. mpush(bytes)
  606. {
  607.    char *str;
  608.  
  609.    str = malloc(5 + bytes + 2);   /* may need 2 extra bytes in do_run() */
  610.    *(char ***)str = Mlist;
  611.    str[4] = 1;
  612.    Mlist = (char **)str;
  613.    return (str + 5);
  614. }
  615.  
  616. mpop_tobase()
  617. {
  618.    register char *next;
  619.    while (Mlist) {
  620.       next = *Mlist;
  621.       if (((char *)Mlist)[4] == 0) {
  622.      free (Mlist);
  623.      Mlist = (char **)next;
  624.      break;
  625.       }
  626.       free (Mlist);
  627.       Mlist = (char **)next;
  628.    }
  629. }
  630.  
  631.  
  632. /*
  633.  * Insert 'from' string in front of 'str' while deleting the
  634.  * first entry in 'str'.  if freeok is set, then 'str' will be
  635.  * free'd
  636.  */
  637.  
  638.  
  639.  
  640. char *
  641. format_insert_string(str, from, freeok)
  642. char *str;
  643. char *from;
  644. int *freeok;
  645. {
  646.    register char *new1, *new2;
  647.    register unsigned char *strskip;
  648.    int len;
  649.  
  650.    for (strskip = (unsigned char *)str; *strskip && *strskip != ' ' && *strskip != ';' && *strskip != '|' && *strskip != 0x80; ++strskip);
  651.    len = strlen(from);
  652.    new1 = malloc((len << 2) + 2);
  653.    preformat(from, new1);
  654.    len = strlen(new1) + strlen(strskip);
  655.    new2 = malloc(len+2);
  656.    strcpy(new2, new1);
  657.    strcat(new2, strskip);
  658.    new2[len+1] = 0;
  659.    free (new1);
  660.    if (*freeok)
  661.       free (str);
  662.    *freeok = 1;
  663.    return (new2);
  664. }
  665.  
  666. find_command(str)
  667. char *str;
  668. {
  669.    int i;
  670.    int len = strlen(str);
  671.  
  672.    if (*str >= '0'  &&    *str <= '9')
  673.       return (1);
  674.    for (i = 0; Command[i].func; ++i) {
  675.       if (strncmp (str, Command[i].name, len) == 0)
  676.      return (i);
  677.    }
  678.    return (0);
  679. }
  680.  
  681. do_help()
  682. {
  683.    register struct COMMAND *com;
  684.    int i= 0;
  685.  
  686.  
  687.    for (com = &Command[2]; com->func; ++com) {
  688.       printf ("%-12s", com->name);
  689.       if (++i  % 6 == 0) printf("\n");
  690.    }
  691.    printf("\n");
  692.    return(0);
  693. }
  694.  
  695.